Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional improvements to Store and Record API #1082

Merged
merged 14 commits into from
Apr 22, 2019
Merged

Additional improvements to Store and Record API #1082

merged 14 commits into from
Apr 22, 2019

Conversation

lbwexler
Copy link
Member

  • Restore 'raw' data property on record.
  • More maintainable handling of name collision
  • Don't require user to delete bad 'id' property on raw data. idSpec always wins.
  • Cleanup to left/right chooser

+ Restore 'raw' data property on record.
+ More maintainable handling of name collision
+ Don't require user to delete bad 'id' property on raw data.  idSpec always wins.
+ Cleanup to left/right chooser
@lbwexler lbwexler requested a review from haynesjm42 April 19, 2019 01:17
Copy link
Member

@amcclain amcclain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like some good cleanups / hardening of this part of our system.

I am still somewhat mystified as to how raw will be used, but if it's helpful it also seems very natural.

@@ -43,20 +42,31 @@ export class Record {
* requiring children to also be recreated.)
*
* @param {Object} c - Record configuration
* @param {Object} c.data - data for constructing the record.
* @param {Object} c.raw - raw data for record.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that apps aren't expected to construct records, but this is still a bit confusing here. How about:

c.data - data used to construct this record, pre-processed if applicable by store.processRawData().
c.raw - the same data, prior to any store pre-processing.

Would that be incrementally more clear?

data/Record.js Outdated
@@ -43,20 +42,31 @@ export class Record {
* requiring children to also be recreated.)
*
* @param {Object} c - Record configuration
* @param {Object} c.data - data for constructing the record.
* @param {Object} c.raw - raw data for record.
* @param {BaseStore} c.store - store containing this record.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Realizing that LocalStore defines idSpec, which means that's what you need to be passing in here. Yet BaseStore also declares interfaces that deal in Records/RecordSets.

We've discussed how we might want to unwind BaseStore, taking LocalStore -> Store and having it be the primary/parent store class. I dunno if we want to deal with that now.

Alternatively we could move idSpec to BaseStore, or adjust the docs here to punt a bit and deal with LocalStore only.


this.id = id;
this.store = store;
this.raw = raw;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add an @member declaration

if (name == 'id') return;
throwIf(
name in this,
`Field name "${name}" cannot be used for data. It is reserved as a top-level property of the Record class.`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great that this check moved into this class.

let data = raw;
if (store.processRawData) {
data = store.processRawData(raw);
throwIf(!data, 'processRawData should return an object. If writing/editing, be sure to return a clone!');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we enforce processRawData always returning a new object? Is there a likely/important use case where we have processRawData making decisions to not edit some objects (and it would be terribly inefficient to force it to clone anyway)?


const rawRec = this._data.find(raw => raw === rec.raw);
rawRec.side = (rec.side === 'left' ? 'right' : 'left');
rec.raw.side = (rec.side === 'left' ? 'right' : 'left');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll be honest - I am not gonna dive into LRChooser code right now, but this seems very weird to be modifying the raw object.

@amcclain
Copy link
Member

@haynesjm42 - Lee and I just talked this over a bunch more and he is going to press forward with some additional refactoring. Looking to collapse BaseStore+LocalStore -> Store + provide an efficient children getter on record (not directly related to this raw data change but will roll it all up into a bigger data package redo).

+ id should not be a field
+ LocalStore -> Store
+ Remove BaseStore
+ Implement record.children, record.allChildren
+ lint
@lbwexler lbwexler requested a review from amcclain April 22, 2019 12:13
@lbwexler lbwexler changed the title + Don't mutate data presented to loadData or updateData Additional improvements to Store and Record API Apr 22, 2019
@lbwexler
Copy link
Member Author

This should be good to review and merge. Thanks to everyone for getting this in a good place. I think we now have a very tight, efficient TreeStore, with a very usable API.

data/impl/RecordSet.js Outdated Show resolved Hide resolved
@haynesjm42 haynesjm42 self-requested a review April 22, 2019 15:28
+ add rootRecords/allRootRecords getters
@lbwexler
Copy link
Member Author

lbwexler commented Apr 22, 2019 via email

Copy link
Member

@haynesjm42 haynesjm42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just a couple minor comments.

Also it occurred to me that we have some logic in Grid which handles determining if the date is hierarchical or not, I wonder if we should move that into Store as a getter?

records.forEach(r => {
const {parentId} = r;
if (parentId) {
let children = ret.get(parentId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this could be const?

@@ -58,7 +57,7 @@ export class StoreCountLabel extends Component {
if (!store) return null;

const includeChildren = withDefault(this.props.includeChildren, false),
count = includeChildren ? store.count : this.rootCount(store),
count = includeChildren ? store.count : store.rootRecords.length,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we've gone back and forth with this a few times, but should we have rootCount on Store for symmetry between the records and rootRecords properties? (I'm fine either way, we can always add it later if we see apps or other components with this kind of code)

*/
@action
removeRecord(id) {
this._all = this._all.removeRecord(id);
removeRecords(ids) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do a ids = castArray(ids)' here just to make it nice and clean for apps to remove a single record (something I tend to do a lot in inline editable grids)

@lbwexler lbwexler merged commit f2fd604 into develop Apr 22, 2019
@lbwexler lbwexler deleted the recordFixes branch April 22, 2019 19:15
@amcclain
Copy link
Member

Great - excellent to see this landed! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants